#include <stdio.h>
#include <string.h>

#include "plat_display.h"
#include "file_map.h"

#define DIS_INFO(...) fprintf(stdout, "\033[32m[DISPLAY_INFO] %s(%d): \033[0m", __FUNCTION__, __LINE__),fprintf(stdout, __VA_ARGS__)
#define DIS_ERR(...) fprintf(stderr, "\033[31m[DISPLAY_ERR] %s(%d): \033[0m", __FUNCTION__, __LINE__),fprintf(stderr, __VA_ARGS__)

//fb基本信息
#define FB_DEV "/dev/fb0"
static FbMapStruct *gFbMap = NULL;
static Image gImage;
static int32_t gFbUsers = 0; //当前使用人数,当最后一个退出时才正真释放内存

static void FbMapInit()
{
    gFbUsers += 1;

    if (gFbMap)
        return;

    gFbMap = FbMapOpen(FB_DEV);
    if (!gFbMap)
        DIS_ERR("FbMapOpen failed \n");
    else
    {
        gImage.Resize(gFbMap->fbInfo.xres, gFbMap->fbInfo.yres, IMAGE_FORMAT_BGRA);
        DIS_INFO("FbMapOpen: %dx%d, %d, %d \n",
            gImage.Info().width,
            gImage.Info().height,
            gImage.Info().pb,
            gImage.Info().format);
    }
}

static void FbMapDeInit()
{
    if (!gFbMap)
        return;

    gFbUsers -= 1;
    if (gFbUsers > 0)
        return;

    FbMapClose(gFbMap);
    gFbMap = NULL;

    gImage.Resize(0, 0);
}

CPlatDisplay::CPlatDisplay()
{
    FbMapInit();
}

CPlatDisplay::~CPlatDisplay()
{
    FbMapDeInit();
}

//获取显示器内存和信息
Image& CPlatDisplay::GetMap()
{
    return gImage;
}

//刷新
void CPlatDisplay::Refresh(int32_t x, int32_t y, int32_t width, int32_t height)
{
    if (!gFbMap)
        return;

    if (height < 1)
        height = gImage.Info().height;
    if (width < 1)
        width = gImage.Info().width;

    if (x < gImage.Info().width &&
        y < gImage.Info().height &&
        x + width > 0 &&
        y + height > 0)
        ;
    else
        return;

    int32_t xBegin = x < 0 ? 0 : x;
    int32_t yBegin = y < 0 ? 0 : y;

    int32_t xEnd = x + width;
    int32_t yEnd = y + height;

    int32_t xSize = (xEnd > gImage.Info().width ? gImage.Info().width - xBegin : xEnd - xBegin) * gImage.Info().pb;
    int32_t ySize = yEnd > gImage.Info().height ? gImage.Info().height - yBegin : yEnd - yBegin;

    int32_t usrLineSize = gImage.Info().width * gImage.Info().pb;
    int32_t disLineSize = gFbMap->fbInfo.xres_virtual * gImage.Info().pb;

    uint8_t *usrPtr = gImage.Mem(xBegin, yBegin).addr;
    uint8_t *disPtr = gFbMap->fb + ((yBegin + gFbMap->fbInfo.yoffset) * gFbMap->fbInfo.xres_virtual + gFbMap->fbInfo.xoffset + xBegin) * gImage.Info().pb;

    for (int32_t i = 0; i < ySize; i++)
    {
        memcpy(disPtr, usrPtr, xSize);
        usrPtr += usrLineSize;
        disPtr += disLineSize;
    }
}
